package cn.sjx.print.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.sjx.print.constants.PrintConstant;
import cn.sjx.print.entity.HtmlRenderData;
import cn.sjx.print.service.BaseRenderFactoryHandler;
import com.itextpdf.text.pdf.BaseFont;
import lombok.extern.slf4j.Slf4j;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.PrettyHtmlSerializer;
import org.htmlcleaner.TagNode;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.File;
import java.io.FileOutputStream;

/**
 * pdf渲染工厂
 *
 * @author sjx
 * @date 2020年05月12日 16:28:33
 */
@Slf4j
public class PdfRenderFactoryUtil extends BaseRenderFactoryHandler {

    /**
     * 渲染
     * 自定义数据并渲染为模板
     *
     * @param templateName    模板名称
     * @param htmlRenderData  填充数据（若dataList为空，则采用druid数据源）
     * @param subTemplateName 子模板名称（在jasperReport中，添加相同个数名称为“SUB_REPORT_[0，1，2......]”；Class属性为“net.sf.jasperreports.engine.JasperReport”的Parameters参数）
     * @return {@link File} pdf文件在系统中的路径
     */
    public static File render(String templateName, HtmlRenderData htmlRenderData, String... subTemplateName) {
        // 定义最终返回结果
        File tempFile = FileUtil.createTempFile("jasper", ".pdf", FileUtil.mkdir(PrintConstant.PDF_TEMP_FILE_PATH),
                true);
        try {
            // 导出为pdf
            JRPdfExporter jrPdfExporter = new JRPdfExporter();
            jrPdfExporter.setExporterInput(new SimpleExporterInput(generateJasperPrint(templateName, htmlRenderData,
                    subTemplateName)));
            jrPdfExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(tempFile));
            jrPdfExporter.exportReport();
        } catch (Exception e) {
            log.error("======> 模板渲染出错，原因：", e);
        }

        return tempFile;
    }

    /**
     * html转pdf
     *
     * @param htmlString html字符串
     * @return {@link File } pdf文件在系统中的路径
     */
    public static File htmlToPdf(String htmlString) {
        File tempFile = FileUtil.createTempFile("jasper", ".pdf", FileUtil.mkdir(PrintConstant.PDF_TEMP_FILE_PATH), true);
        try {
            if (StrUtil.isBlank(htmlString)) {
                return tempFile;
            }

            // 页面中字体不能使用中文，需要使用英文名称，而且是大小写敏感的！例如宋体的英文名称是 SimSun(注意不是simsun！，首字母都是大写的)
            // 错误写法：font-family:宋体 或者  font-family:simsun
            // 正确写法：font-family:SimSun 或者 font-family:SimHei
            if (StrUtil.contains(htmlString, "font-family: \\'宋体\\'")) {
                htmlString = StrUtil.replace(htmlString, "font-family: \\'宋体\\'", "font-family: SimSun");
            }
            if (StrUtil.contains(htmlString, "font-family: 宋体")) {
                htmlString = StrUtil.replace(htmlString, "font-family: 宋体", "font-family: SimSun");
            }
            if (StrUtil.contains(htmlString, "\\'宋体\\'")) {
                htmlString = StrUtil.replace(htmlString, "\\'宋体\\'", "SimSun");
            }

            // region 清理不规范标签
            // 主要用于处理 报错：org.xhtmlrenderer.util.XRRuntimeException: Can't load the XML resource (using TRaX transformer). org.xml.sax.SAXParseException: The element type "meta" must be terminated by the matching end-tag "</meta>".
            CleanerProperties props = new CleanerProperties();
            props.setTranslateSpecialEntities(true);
            props.setTransResCharsToNCR(true);
            props.setOmitComments(true);
            TagNode tagNode = new HtmlCleaner(props).clean(htmlString);
            htmlString = new PrettyHtmlSerializer(props).getAsString(tagNode, CharsetUtil.UTF_8);
            // endregion

            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(htmlString);
            // 解决中文支持问题
            asianFont(renderer);

            // 解决图片的相对路径问题,图片使用base64编码即可,否则就得如下使用,建议使用base64
            // renderer.getSharedContext().setBaseURL("http://www.baidu.com/test.jpg");
            // renderer.getSharedContext().setReplacedElementFactory(new B64ImgReplacedElementFactory());

            renderer.layout();
            FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
            renderer.createPDF(fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tempFile;
    }

    /**
     * 亚洲字体
     *
     * @param renderer 渲染器
     */
    private static void asianFont(ITextRenderer renderer) {
        try {
            ITextFontResolver fontResolver = renderer.getFontResolver();

            if (SystemUtil.getOsInfo().isLinux()) {
                fontResolver.addFont(PrintConstant.LINUX_FONT_FILE_PREFIX + "simsun.ttc", BaseFont.IDENTITY_H,
                        BaseFont.NOT_EMBEDDED);
                fontResolver.addFont(PrintConstant.LINUX_FONT_FILE_PREFIX + "msyh.ttc", BaseFont.IDENTITY_H,
                        BaseFont.NOT_EMBEDDED);
            } else {
                fontResolver.addFont(PrintConstant.WINDOWS_FONT_FILE_PREFIX + "simsun.ttc", BaseFont.IDENTITY_H,
                        BaseFont.NOT_EMBEDDED);
                fontResolver.addFont(PrintConstant.WINDOWS_FONT_FILE_PREFIX + "msyh.ttc", BaseFont.IDENTITY_H,
                        BaseFont.NOT_EMBEDDED);
            }
        } catch (Exception e) {
            log.error("中文字体加载失败", e);
        }
    }

}